package com.linkgie.galaxyframework.fileservice;

import java.io.InputStream;
import java.util.Iterator;
import java.util.Properties;

/**
 * 文件存储服务；
 * 
 * @author Hike
 *
 */
public interface FileService {

	/**
	 * 获取文件对象信息；
	 * <p>
	 * 
	 * 如果文件存在，则返回文件对象；如果文件不存在，则返回 null；
	 * <p>
	 * 
	 * 如果 fileId 格式不正确，则抛出 IllegalFileSpecificationException 异常；
	 * 
	 * @param fileId 文件ID；
	 * @return
	 */
	FileObject getFile(String fileId) throws IllegalFileSpecificationException;

	/**
	 * 读文件内容；
	 * 
	 * @param fileId 文件ID；
	 * @return 如果文件存在，则返回读取文件内容的输入流；如果文件不存在，则返回 null；
	 */
	InputStream readFile(String fileId) throws FileStorageException;

	/**
	 * 创建文件；
	 * <p>
	 * 
	 * 当两个文件的名称、类型、内容、存储类型（临时区/持久区）都完全相同时，被认为是相同的文件。
	 * <p>
	 * 
	 * 与 {@link #addFile(String, String, boolean, byte[])} 方法不同，
	 * 如果已经存在包括内容和名称都完全相同的文件，则会产生文件存储冲突，引发 {@link FileRepeatedException} 异常。
	 * 
	 * @param name         文件名； 允许为空；
	 * @param type         文件类型； 允许为空；
	 * @param temporary    是否以临时文件方式创建；
	 * @param contentBytes 文件内容的字节数组；
	 * @return
	 */
	default FileObject createFile(String name, String type, boolean temporary, byte[] contentBytes)
			throws FileRepeatedException {
		return createFile(name, type, temporary, null, contentBytes);
	}

	/**
	 * 创建文件；
	 * <p>
	 * 
	 * 当两个文件的名称、类型、内容、存储类型（临时区/持久区）都完全相同时，被认为是相同的文件。
	 * <p>
	 * 
	 * 与 {@link #addFile(String, String, boolean, byte[])} 方法不同，
	 * 如果已经存在包括内容和名称都完全相同的文件，则会产生文件存储冲突，引发 {@link FileRepeatedException} 异常。
	 * 
	 * @param name         文件名； 允许为空；
	 * @param type         文件类型； 允许为空；
	 * @param temporary    是否以临时文件方式创建；
	 * @param attributes   文件属性表；
	 * @param contentBytes 文件内容的字节数组；
	 * @return
	 */
	FileObject createFile(String name, String type, boolean temporary, Properties attributes, byte[] contentBytes)
			throws FileRepeatedException;

	/**
	 * 加入文件；
	 * <p>
	 * 
	 * 当两个文件的名称、类型、内容、存储类型（临时区/持久区）都完全相同时，被认为是相同的文件。
	 * <p>
	 * 
	 * 与 {@link #createFile(String, String, boolean, byte[])} 方法不同，
	 * 如果已经存在包括内容和名称都完全相同的文件，则直接返回对应的 FileObject 而不会引发异常。
	 * 
	 * @param name         文件名； 允许为空；
	 * @param type         文件类型； 允许为空；
	 * @param temporary    是否以临时文件方式创建；
	 * @param contentBytes 文件内容的字节数组；
	 * @return
	 */
	default FileObject addFile(String name, String type, boolean temporary, byte[] contentBytes) {
		return addFile(name, type, temporary, null, contentBytes);
	}

	/**
	 * 加入文件；
	 * <p>
	 * 
	 * 当两个文件的名称、类型、内容、存储类型（临时区/持久区）都完全相同时，被认为是相同的文件。
	 * <p>
	 * 
	 * 与 {@link #createFile(String, String, boolean, byte[])} 方法不同，
	 * 如果已经存在包括内容和名称都完全相同的文件，则直接返回对应的 FileObject 而不会引发异常。
	 * 
	 * @param name         文件名； 允许为空；
	 * @param type         文件类型； 允许为空；
	 * @param temporary    是否以临时文件方式创建；
	 * @param attributes   文件属性表；
	 * @param contentBytes 文件内容的字节数组；
	 * @return
	 */
	FileObject addFile(String name, String type, boolean temporary, Properties attributes, byte[] contentBytes);

	/**
	 * 保存文件；
	 * 
	 * <p>
	 * 注：与 {@link #addFile(String, String, boolean, byte[])} 和
	 * {@link #createFile(String, String, boolean, byte[])} 方法不同，
	 * 
	 * 此方法会根据文件的扩展名，判断文件类型，做相应处理；
	 * 例如，针对图片，则自动生成缩略图；
	 * 
	 * @param fileName     文件名；
	 * @param temporary    是否作为临时文件，保存在临时存储区；
	 * @param contentBytes 文件的内容；
	 * @return
	 */
	FileObject saveFile(String fileName, boolean temporary, byte[] contentBytes);

	/**
	 * 发布当前机构的文件；
	 * 
	 * <p>
	 * 
	 * 要求调用者为当前机构的机构管理员；
	 * 
	 * @param fileId
	 */
	void publishFile(String fileId);

	/**
	 * 发布文件；
	 * 
	 * @param fileId      文件ID；
	 * @param description 描述；
	 * @param attributes  属性；
	 */
	void publishFile(String fileId, String description, Properties attributes);

	/**
	 * 将已发布的文件收回；
	 * 
	 * @param fileId 文件ID；
	 */
	void takeoffFile(String fileId);

	/**
	 * 将临时文件提交为持久文件；
	 * 
	 * 如果临时文件仍然存在，则将文件从临时存储区移动到持久存储区，并返回新的文件对象；<br>
	 * 如果临时文件不存在，则直接返回 NULL；
	 * 
	 * @param fileId
	 * @return
	 */
	FileObject commitTemporayFile(String fileId);

	/**
	 * 设置文件属性；
	 * 
	 * @param fileId     文件Id；
	 * @param attributes 文件属性；
	 * @return
	 */
	FileObject setFileAttributes(String fileId, Properties attributes);

	/**
	 * 存储服务的参数；
	 * 
	 * @return
	 */
	StorageSettings getSettings();

	/**
	 * 获取当前组织机构的文件清单；
	 * <p>
	 * 如果当前机构未授权文件服务，则返回空的迭代器；
	 * 
	 * @param subject
	 * @return
	 */
	Iterator<FileObject> getFilesOfCurrentOrganization();

	/**
	 * 获取当前组织机构的指定门类的文件清单；
	 * <p>
	 * 如果当前机构未授权文件服务，则返回空的迭代器；
	 * 
	 * @param subject
	 * @return
	 */
	Iterator<FileObject> getFilesOfCurrentOrganization(String subject);

	/**
	 * 获取当前组织机构的指定门类的文件清单；
	 * <p>
	 * 如果当前机构未授权文件服务，则返回空的迭代器；
	 * 
	 * @param subject 门类；
	 * @param status  状态；如果参数为 null ，则返回结果不区分任何状态；
	 * @return
	 */
	Iterator<FileObject> getFilesOfCurrentOrganization(String subject, FileStatus status);
}
